#include "HY1C_out.h"
/* ========================================================================
 * vcalmerge - reads original and vicarious data from L2 file or files
 *	       and writes valid cross-calibration data into an HDF file
 *
 * Synopsis:
 *
 *   vcalmerge par=parfile 
 *
 * Description:
 * 
 * Modification history:
 *
 *     Programmer     Organization      Date       Description of change
 *   --------------   ------------    --------     ---------------------
 *   Ewa Kwiatkowska   SAIC        27 August 2003    Original development
 *   Ewa Kwiatkowska   SAIC       6 November 2006    getl1rec change
 *   Ewa Kwiatkowska   SAIC        9 October 2007    complete redevelopment
 *					        to extract xcal data from L2 files
 *   Joel Gales        Futuretech 24 October 2012    Fix HDF sensor attribute bug
 *
 * ======================================================================== */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <libgen.h>
#include <math.h>

#include "seabin.h"

#include "l12_proto.h"
#include "mscal_struc.h"
#include "hdf.h"
#include <setupflags.h>


int msxcal_usage(char *prog);
int msl2cal_input(int argc, char **argv, inputstr *input_str);
int msl2cal_get_item(char *arg, inputstr *input_str);
int msl2cal_input_init(inputstr *input_str);
int msl2cal_par_file(char *pfile, inputstr *input_str);


/* -------------------------------------------------------------------- *
 *                              main                                    *
 * -------------------------------------------------------------------- */
int main(int argc, char *argv[])
{

    int32_t   iscan    = 0;          /* input scan number                  */
    int32_t   oscan    = 0;          /* output scan number                 */
    int32_t   spix     = 0;          /* start pixel for subscene process   */
    int32_t   epix     = -1;         /* end pixel for subscene process     */
    int32_t   ipix;
    int32_t   cpix;
    int32_t   dpix;
    int32_t   cscan;
    int32_t   sscan    = 0;          /* start scan for subscene process    */
    int32_t   escan    = -1;         /* end scan for subscene process      */
    int32_t   dscan;
    int32_t   opix     = 0;          /* output pixels number               */
    int32_t   npix     = 0;          /* Number of output pixels per scan   */
    int32_t   nscan    = 0;          /* Number of output scans             */
    int32_t   npixs    = 0;
    int32_t   i, j, l, ll, np, k, kk, aa, tgs, tge, Ltinx, vLtinx;
    int    status, isMODIS;

    l2_prod   *l2_str;	           /* input data for L2 calibrator         */
    filehandle l2file;           /* input metadata for L2 calibrator     */
    int32_t       nbands, nprods, *Lambda_p;
    float32   *fp32;
    int8      *iptr;
    int32_t       nfiles;
    off_t      size;
    struct     stat bufor;
    int32      sd_id;

    uint32_t  flagusemask;
    uint32_t  required_mask;
    
    char        *xcalfile;
    inputstr    input;
    mscalstr    calstr;
    char        l2_flags[1000];
    
    

    if (argc == 1) {
      msxcal_usage(argv[0]);
      exit(FATAL_ERROR);
    }


    /* Parse input parameters */
    if (msl2cal_input(argc, argv, &input) != 0) {
        HY1C_out("-E- %s: Error parsing input parameters, exiting...\n",argv[0]);
        exit(FATAL_ERROR);
    }
    
    if (input.ifile[0] == '\0') {
        HY1C_out("-E- %s: No L2 file provided, exiting...\n",argv[0]);
        exit(FATAL_ERROR);
    }
    
    if (input.ofile[0] == '\0') {
        HY1C_out("-E- %s: No name given to the hdf output file with cross-cal pixel data\n",argv[0]);
	strcpy(input.ofile, input.ifile[0]);
	strcat(input.ofile, "_xcal.hdf\x0");
	HY1C_out("     Assuming the name %s", input.ofile);
    }
    xcalfile = (char *)input.ofile;
   

    if (access(input.ifile[0], F_OK) || access(input.ifile[0], R_OK)) {
        HY1C_out("-E- %s: Input file '%s' does not exist or cannot open.\n",
               argv[0], input.ifile[0]);
        exit(FATAL_ERROR);
    }
    
    
    /* Determine number of input HDF files. */
    for (i=0, nfiles=0; i<MAXNFILES; i++, nfiles++)
      	if (input.ifile[i][0] == '\0')
            break;
   
   
    if (input.xcalbox > 0 && nfiles > 1) {
        HY1C_out("-E- %s: Calibration box extraction cannot be applied on multiple files.\n",argv[0]);
        exit(FATAL_ERROR);
    }
    
    HY1C_out("\n");
    
   

    /*									*/
    /* Open L2 files and check the products and sensor name             */
    /*                                                                  */
     	           
    if ( (l2_str = (l2_prod *)malloc(nfiles*sizeof(l2_prod))) == NULL ) {
       HY1C_out("-E- %s: Error allocating memory for reading L2 data.\n",argv[0]);
       exit(FATAL_ERROR);
    }
    for (i=0; i<nfiles; i++) {
    
       filehandle_init(&l2file);
       strcpy(l2file.name, input.ifile[i]);
       if (getFormat(&l2file) != FMT_MSL12L2) {
	    HY1C_out("-E- %s: Input file is not in the MSL12 L2 HDF format %s.\n", argv[0], input.ifile[i]);
	    exit(FATAL_ERROR);
       }
       /* grab the target sensor name from the L2 meta-data */
       if ( i==0 ) 
            calstr.sensorID = l2file.sensorID; 
       else if (calstr.sensorID != l2file.sensorID) {
            HY1C_out("-E- %s: Mixing L2 data from different sensors, %s and %s.\n",
                 argv[0], sensorName[calstr.sensorID], sensorName[l2file.sensorID]);
	    exit(FATAL_ERROR);
       }
       
       l2_str[i].nrec = 0;
       l2_str[i].nsamp = 0;
       if ( openL2(input.ifile[i], 0x0, &l2_str[i]) ) {
            HY1C_out("-E- %s: Error reading L2 data %s.\n", argv[0], input.ifile[i]);
            exit(FATAL_ERROR);
       }
       if (l2_str[i].l2_flags == NULL) {
          HY1C_out("-E- %s: l2_flags are missing from the L2 data file %s.\n", argv[0], l2_str[i].filename);
          exit(FATAL_ERROR);
       }
       if (l2_str[i].mside == NULL) {
          HY1C_out("-E- %s: mside is missing from the L2 data file %s.\n", argv[0], l2_str[i].filename);
          exit(FATAL_ERROR);
       }
       if (l2_str[i].detnum == NULL) {
          HY1C_out("-E- %s: detnum is missing from the L2 data file %s.\n", argv[0], l2_str[i].filename);
          exit(FATAL_ERROR);
       }
       if (l2_str[i].pixnum == NULL) {
          HY1C_out("-E- %s: pixnum is missing from the L2 data file %s.\n", argv[0], l2_str[i].filename);
          exit(FATAL_ERROR);
       }
    }
   
    
    
    /* Make sure numbers of L2 products are identical for every input L2 file */
    /* ---------------------------------------------------------------------- */
    status = 0;
    for (i=1; i<nfiles; i++)
    if (l2_str[i-1].nprod != l2_str[i].nprod) {
	HY1C_out("-E- %s: Number of products for %s (%d) differs from %s (%d)\n",argv[0],
	 l2_str[i-1].filename, l2_str[i-1].nprod, l2_str[i].filename, l2_str[i].nprod);
	status = -1;
    }
    if (status == -1) exit(FATAL_ERROR);


    /* Make sure L2 product names are identical for every input L2 file */
    /* ---------------------------------------------------------------- */
    status = 0;
    for (i=1; i<nfiles; i++)
     for (j=0; j<l2_str[i].nprod; j++)
      	if (strcmp(l2_str[i-1].prodname[j], l2_str[i].prodname[j]) != 0) {
		HY1C_out("-E- %s: Product %d for %s (%s) differs from %s (%s)\n",argv[0],
	        j, l2_str[i-1].filename, l2_str[i-1].prodname[j], l2_str[i].filename, l2_str[i].prodname[j]);
		status = -1;
    	}
    if (status == -1) exit(FATAL_ERROR);

  
 
    /* Make sure all L2 products required for the xcalibration are present  */
    /* -------------------------------------------------------------------- */
    l = 0; ll = 0;
    Ltinx   = -1;
    vLtinx  = -1;
    nprods = 0;
    for (j=0; j<l2_str[0].nprod; j++) {
	if (strncmp(l2_str[0].prodname[j], "l2_flags",  8) == 0) continue;
        if (strncmp(l2_str[0].prodname[j], "Lt_",  3) == 0) {
	   if (Ltinx < 0) Ltinx = j;
	   ++l;
        }
        if (strncmp(l2_str[0].prodname[j], "vLt_",  4) == 0) {
	   if (vLtinx < 0) vLtinx = j;
	   ++ll;
        }
	++nprods;
    }
    if (l == 0) {
        HY1C_out("-E- %s: Lt TOA calibration data are missing from the L2 data file %s.\n", argv[0], l2_str[0].filename);
        exit(FATAL_ERROR);
    }
    if (ll == 0) {
        HY1C_out("-E- %s: vLt TOA calibration data are missing from the L2 data file %s.\n", argv[0], l2_str[0].filename);
        exit(FATAL_ERROR);
    }
   
    nbands = rdsensorinfo(calstr.sensorID, 0, NULL, NULL);
    calstr.nbands = nbands;
    calstr.nprods = nprods;
   
    if ((calstr.l2prods = (prname *)malloc(nprods*sizeof(prname))) == NULL) {
        HY1C_out("-E- : Error allocating memory to L2 product names.\n");
        exit(FATAL_ERROR);
    }
    nprods = 0;
    for (j=0; j<l2_str[0].nprod; j++)
        if (strcmp(l2_str[0].prodname[j], "l2_flags") != 0) strcpy(calstr.l2prods[nprods++], l2_str[0].prodname[j]);
   
    if ((calstr.Lambda = (int32_t *)malloc(nbands*sizeof(int32_t))) == NULL) {
        HY1C_out("-E- : Error allocating memory to Lambda vector.\n");
        exit(FATAL_ERROR);
    }
   
    i = rdsensorinfo(calstr.sensorID, 0, "Lambda", (void **) &Lambda_p);
   
    for (i=0; i<calstr.nbands; i++) calstr.Lambda[i] = Lambda_p[i];
     
    
     
    l2_flags[0] = '\0';
    for (i=0; i<NFLAGS; i++) {
    	 strcat(l2_flags, l2_flag_lname[i]);
	 if (i<NFLAGS-1) strcat(l2_flags, ",\0");
    }
    l = strlen(l2_flags);
    setupflags(l2_flags, input.flaguse, &flagusemask, &required_mask, &status );
    if (status < 0) {
         HY1C_out("-E- %s: Error setting up L2 flags.\n",argv[0]);
         exit(FATAL_ERROR);
    }     
    
    l = strlen(input.input_parms);
    if ((calstr.input_parms = (char *)malloc((l+1)*sizeof(char))) == NULL) {
         HY1C_out("-E- %s line %d: Error allocating memory to MScalmerge input parameter text.\n",__FILE__,__LINE__);
       	 exit(FATAL_ERROR);
    }
    strncpy(calstr.input_parms, input.input_parms, l);
    calstr.input_parms[l] = '\x0';
	    
    HY1C_out("\n");
    ll = 0;

    	
    for (i=0; i<nfiles; i++) {
	    
	
        HY1C_out("\n%s: Appending file %d of %d, %s.\n", argv[0], (i+1), nfiles, input.ifile[i]);


        /* Set the end pixel if it was not set by command argument	        */
        if (input.epixl == -1 || input.epixl > l2_str[i].nsamp)
            input.epixl = l2_str[i].nsamp;
        if (input.eline == -1 || input.eline > l2_str[i].nrec)
            input.eline = l2_str[i].nrec;
        if (input.spixl < 1)
            input.spixl = 1;
        if (input.sline < 1)
            input.sline = 1;
	    
        spix  = MAX(input.spixl - 1, 0);
        epix  = MIN(input.epixl - 1, l2_str[i].nsamp-1);
        dpix  = MAX(input.dpixl,1);
        sscan = MAX(input.sline - 1, 0);
        escan = MIN(input.eline - 1, l2_str[i].nrec-1);
        dscan = MAX(input.dline,1);

        if (sscan > escan || spix > epix) {
            HY1C_out("-E- %s: scan and pixel limits make no sense.\n", argv[0]);
            HY1C_out(" start scan  = %d\n",sscan+1);
            HY1C_out(" end   scan  = %d\n",escan+1);
            HY1C_out(" start pixel = %d\n",spix +1);
            HY1C_out(" end   pixel = %d\n",epix +1);
            exit( FATAL_ERROR );
        }

        npix  = (epix  - spix)/dpix  + 1;
        nscan = (escan - sscan)/dscan + 1;
    
        if (input.xcalbox > 0 && ((epix-spix+1) < l2_str[i].nsamp || (escan-sscan+1) < l2_str[i].nrec)) { 
	    HY1C_out("Xcalbox parameter will be applied along with spixl/sline, epixl/eline parameters\n");
        }
    
    
        if (input.xcalbox > 0) {
	
    	    if (input.xcalboxcenter[0] > 0) cpix = spix+input.xcalboxcenter[0]-1; else cpix = spix+npix/2;
	    l = dpix*(input.xcalbox-1);
	    ipix = cpix - l/2;
	    if (ipix < spix) {
	         HY1C_out("-E- %s: pixel size of the central box exceeds the scene size, spix %d, sbox %d\n",
	           argv[0],(int)spix,(int)ipix);
	         exit( FATAL_ERROR );
	    }
	    spix = ipix;
	    ipix += l;
	    if (ipix > epix) {
	         HY1C_out("-E- %s: pixel size of the central box exceeds the scene size, epix %d, sbox %d\n",
	    	    argv[0],(int)epix,(int)ipix);
	         exit( FATAL_ERROR );
	    }
	    epix = ipix;
	
	    if (input.xcalboxcenter[1] > 0) cscan = sscan+input.xcalboxcenter[1]-1; else cscan = sscan+nscan/2;
	    l = dscan*(input.xcalbox-1);
	    iscan = cscan - l/2;
	    if (iscan < sscan) {
	         HY1C_out("-E- %s: pixel size of the central box exceeds the scene size, sscan %d, sbox %d\n",
	        	argv[0],(int)sscan,(int)iscan);
	         exit( FATAL_ERROR );
	    }
	    sscan = iscan;
	    iscan += l;
	    if (iscan > escan) {
	         HY1C_out("-E- %s: pixel size of the central box exceeds the scene size, escan %d, sbox %d\n",
	    	    argv[0],(int)escan,(int)iscan);
	         exit( FATAL_ERROR );
	    }
	    escan = iscan;
	    npix = input.xcalbox;
	    nscan = input.xcalbox;
        }

        if ( (iptr = (int8 *)malloc(nscan*sizeof(int8))) == NULL ) {
            HY1C_out("-E- %s: Error allocating memory to the pixel index.\n",argv[0]);
            exit(FATAL_ERROR);
        }

    	np    = 0;
	npixs = 0;
    	oscan = 0;
    	for (iscan = sscan; iscan <= escan; iscan += dscan) {
    
	    if (readL2(&(l2_str[i]), i, iscan, vLtinx, NULL)) {
                  HY1C_out("%s: Error reading L2 data file %s at scan %d.\n",
                       argv[0], l2_str[i].filename, iscan);
                  continue;
      	    }
            if ((iscan % 500) == 0) HY1C_out("Selecting valid pixels for scan %d\n", iscan);

      	    opix = 0;
	    l = 0;
      	    for (ipix = spix; ipix <= epix; ipix += dpix) {
	
	    	if (( l2_str[i].l2_flags[ipix] & flagusemask ) == 0 && l2_str[i].l2_data[vLtinx*l2_str[i].nsamp+ipix] > 0.0) {
		    l = 1;
		    ++npixs;
	    	}
      	    	++opix;
	    }
	  
      	    if (opix != npix) {
           	HY1C_out("%s: Error: Incorrect number of pixels %d obtained in the scan %d.\n", argv[0], opix, oscan);
            }
	    		
	    if (l) iptr[oscan] = 1; else iptr[oscan] = 0;
	    ++oscan;
    	}
	
	
	if (npixs) {

   
            l = alloc_calstr(1L, npixs, &calstr);
    
	    strcpy(calstr.filenames[0], input.ifile[i]);
	

    	    oscan = 0;
    	    for (iscan = sscan; iscan <= escan; iscan += dscan) if (iptr[oscan++]) {
    
	        if (readL2(&(l2_str[i]), i, iscan, -1, NULL)) {
                      HY1C_out("%s: Error reading L2 data file %s at scan %d.\n",
                           argv[0], l2_str[i].filename, iscan);
                      continue;
      	        }
                if ((iscan % 500) == 0) HY1C_out("Storing pixels at scan %d\n", iscan);
	
      	        opix = 0;
      	        for (ipix = spix; ipix <= epix; ipix += dpix) {
	
	    	    if (( l2_str[i].l2_flags[ipix] & flagusemask ) == 0 && l2_str[i].l2_data[Ltinx*l2_str[i].nsamp+ipix] > 0.0 && l2_str[i].l2_data[vLtinx*l2_str[i].nsamp+ipix] > 0.0) {
	    
	    	        calstr.fileID[np] = 0;
	    	        calstr.year[np]   = (int16) l2_str[i].year;
	    	        calstr.day[np]    = (int16) l2_str[i].day;
	    	        calstr.msec[np]   = (int32) l2_str[i].msec;
	    	        calstr.iscan[np]  = (int16) iscan;
	    	        calstr.mside[np]  = (uint8)(l2_str[i].mside [iscan]);
	    	        calstr.detnum[np] = (uint8)(l2_str[i].detnum[iscan]);
	    	        calstr.pixnum[np] = (int16)(l2_str[i].pixnum[ipix]);
	    	        calstr.lon[np]    = l2_str[i].longitude[ipix];
	    	        calstr.lat[np]    = l2_str[i].latitude [ipix];
			   
		        l = 0;
		        for (j=0; j<calstr.nprods; j++) {

    			    if (strcmp(calstr.l2prods[j], "l2_flags") == 0) ;
			    else
    			    if (strcmp(calstr.l2prods[j], "mside") == 0) ;
			    else
    			    if (strcmp(calstr.l2prods[j], "detnum") == 0) ;
			    else
    			    if (strcmp(calstr.l2prods[j], "pixnum") == 0) ;
			    else {
			         calstr.ddata[l*npixs+np] = (float32)(l2_str[i].l2_data[j*l2_str[i].nsamp+ipix]);
			         ++l;
      	     		    }

		        }
		        ++np;
	    	    }

      	    	    ++opix;
	        }
	  
      	        if (opix != npix) {
           	    HY1C_out("%s: Error: Incorrect number of pixels %d obtained in the scan %d.\n", argv[0], opix, oscan);
                }
			
    	    }
	
	
	    if ((np > 0 && input.xcalpervalid <= 0) || (input.xcalpervalid > 0 && np >= npix*nscan*input.xcalpervalid/100 )) {	   
   

	        if (np < npixs) {
		    l = 0;
	            for (j=0; j<calstr.nprods; j++) {
		        if (strcmp(calstr.l2prods[j], "l2_flags") == 0) ;
		        else
    		        if (strcmp(calstr.l2prods[j], "mside") == 0) ;
		        else
    		        if (strcmp(calstr.l2prods[j], "detnum") == 0) ;
		        else
    		        if (strcmp(calstr.l2prods[j], "pixnum") == 0) ;
		        else {
		            if (l > 0) {
		    	        if ((fp32 = (float32 *)memmove((void *)&(calstr.ddata[l*np]), (const void *)&(calstr.ddata[l*npixs]), sizeof(float32)*np)) == NULL) {
	        	             HY1C_out("-E- %s: Problem reallocating memory to data_cal\n", argv[0]);
	        	             exit(FATAL_ERROR);
		    	        }
	                    }
		            ++l;
	                }
	            }
		}
		
	        calstr.npixs = np;
	        ll += np;
	
	        /*					 		      */
    	        /* Output pixel-by-pixel HDF file with cross-cal data     */
    	        /*					 		      */    
    
    	        if (crosscal_append(xcalfile, calstr) != LIFE_IS_GOOD) {
	            HY1C_out("%s Error: Problem writing to the HDF file %s\n", argv[0], input.ofile);
	            exit(FATAL_ERROR);
    	        }

    
    	        sd_id = SDstart(input.ofile, DFACC_RDONLY);
    	        if (sd_id == FAIL) {
		    size = 0;
    	        }
    	        else {
		    SDend(sd_id);
		    if (stat((const char *)input.ofile, &bufor) != 0) {
	    	        HY1C_out("%s Error: Problem checking the status of the HDF file %s\n", argv[0], input.ofile);
	    	        exit(FATAL_ERROR);
    		    }
		    size = bufor.st_size;
    	        }
	    	    
	        if (size >= 2000000000L) {
	    	    HY1C_out("%s Error: Size of the calidation HDF output file exceeded 2GB\n", argv[0]);
		    HY1C_out("   Files starting from the %d file (%s) will not be appended\n", i+1, input.ifile[i]);
	    	    exit(FILESIZE_ERROR);
    	        }	    
	    
    	    }
	    	  
	    if (i == nfiles-1) free_calstr(calstr, 1); else free_calstr(calstr, 0);
	    
    	}
	
	    
    	if (input.xcalpervalid <= 0 && np <= 0) {
    	     HY1C_out("%s: No valid cross-calibration pixels in file %s\n", argv[0], input.ifile[i]);
    	} else 
    	if (input.xcalpervalid > 0 && np < npix*nscan*input.xcalpervalid/100 ) {
    	     HY1C_out("%s: Insufficient number of valid cross-calibration pixels, %d in file %s\n", argv[0], npixs, input.ifile[i]);
	}
	
	
        free(iptr);
	    	
    }     
      
    exit(SUCCESS);
    
}





int msxcal_usage(char *prog)
{
  HY1C_out("%s %s (%s %s)\n",prog,VERSION,__DATE__,__TIME__);
  HY1C_out("Usage: %s argument-list\n",prog);
  HY1C_out("\n");
  HY1C_out(" The argument-list is a set of keyword=calue pairs. The arguments can\n");
  HY1C_out(" be specified on the commandline, or put into a parameter file, or the\n");
  HY1C_out(" two methods can be used together, with commandline over-riding.\n");
  HY1C_out("\n");
  HY1C_out(" The list of calid keywords follows:\n");
  HY1C_out("\n");
  HY1C_out("   par=input parameter file\n");
  HY1C_out("\n");
  HY1C_out("   ifile=input L2 file name with Lt and vLt products for the sensor cross-calibration\n");
  HY1C_out("   ifile[#]=input L2 file names with Lt and vLt products for the sensor cross-calibration\n");
  HY1C_out("   ilist=name of the ASCII file with names of input L2 files for the sensor cross-calibration\n");
  HY1C_out("   ofile=output cross-calbration HDF file\n");
  HY1C_out("   spixl=start pixel number (default=1)\n");
  HY1C_out("   epixl=end pixel number (default=the last pixel)\n");
  HY1C_out("   dpixl=pixel subsampling intercal (default=1)\n");
  HY1C_out("   sline=start line number (default=1)\n");
  HY1C_out("   eline=end line number (default=the last line)\n");
  HY1C_out("   dline=line subsampling intercal (default=1)\n");
  HY1C_out("   flaguse=flags used in selecting data from il2file\n");
  HY1C_out("   xcalbox=pixel size of the central box in the L2 scene (e.g. 5 pixels around MOBY) to be extracted into xcalfile for the cross-calibration, default=0-whole L2\n");
  HY1C_out("   xcalboxcenter=[ipix,iscan] central pixel (values 1..n) and scan (values 1..m) of the box in the L2 scene, default=[0,0]-center of the L2 scene\n");
  HY1C_out("   xcalpervalid=min percent of valid cross-calibration pixels within the box, default=0 means at least 1 pixel\n");
  
  HY1C_out("\n\n");
  return 0;
}


int msl2cal_input_init(inputstr *input_str)
{
  int   i;

  for (i=0; i<MAXNFILES; i++) 
    input_str->ifile [i][0] = '\0';
  input_str->ofile      [0] = '\0';
  input_str->input_parms[0] = '\0';
  strcpy(input_str->flaguse, "ATMFAIL,LAND,HIGLINT,MODGLINT,HILT,STRAYLIGHT,CLDICE,COCCOLITH,LOWLW,CHLFAIL,CHLWARN,NAVWARN,ABSAER,MAXAERITER,ATMWARN,HISOLZEN,NAVFAIL,FILTER,SSTWARN,SSTFAIL,NEGLW,TURBIDW\0");

  input_str->spixl =  1;
  input_str->epixl = -1;
  input_str->dpixl =  1;
  input_str->sline =  1;
  input_str->eline = -1;
  input_str->dline =  1;

  input_str->xcalbox     = 0;
  input_str->xcalboxcenter[0] = 0;
  input_str->xcalboxcenter[1] = 0;
  input_str->xcalpervalid = 0;

  return 0;
}




int msl2cal_input(int argc, char **argv, inputstr *input_str)
{
  int i, iret;
  char str_buf[FILENAME_MAX] = "", buf[3000];
  
  /*                                                                  */
  /* Set input calues to defaults                                     */
  /*                                                                  */
  if ( msl2cal_input_init( input_str ) != 0 ) {
      HY1C_out("-E- %s Line %d: Error initializing input structure.\n",__FILE__,__LINE__);
      return(-1);
  }

  /*                                                                  */
  /* Loop through command arguments and update input struct           */
  /*                                                                  */
  for (i=1; i<argc; i++) {

    iret = msl2cal_get_item(argv[i], input_str);
    if (iret != 0) {
      HY1C_out("-E- %s Line %d: Error reading input parameters.\n", __FILE__,__LINE__);
      return(-1);
    }
  }
  

  /*                                                                  */
  /* Build string of input parameters for meta-data documentation     */
  /*                                                                  */

  if (input_str->ofile[0] != '\0') {
    sprintf(str_buf, "OFILE = %s", input_str->ofile);
    strcat(input_str->input_parms, str_buf);
    strcat(input_str->input_parms, "\n");
  }
  
  sprintf(buf, "FLAGUSE = %s", input_str->flaguse);
  strcat(input_str->input_parms, buf);
  strcat(input_str->input_parms, "\n");

  sprintf(str_buf, "SPIXL = %5d", input_str->spixl);
  strcat(input_str->input_parms, str_buf);
  strcat(input_str->input_parms, "\n");

  sprintf(str_buf, "EPIXL = %5d", input_str->epixl);
  strcat(input_str->input_parms, str_buf);
  strcat(input_str->input_parms, "\n");

  sprintf(str_buf, "DPIXL = %5d", input_str->dpixl);
  strcat(input_str->input_parms, str_buf);
  strcat(input_str->input_parms, "\n");

  sprintf(str_buf, "SLINE = %5d", input_str->sline);
  strcat(input_str->input_parms, str_buf);
  strcat(input_str->input_parms, "\n");

  sprintf(str_buf, "ELINE = %5d", input_str->eline);
  strcat(input_str->input_parms, str_buf);
  strcat(input_str->input_parms, "\n");

  sprintf(str_buf, "DLINE = %5d", input_str->dline);
  strcat(input_str->input_parms, str_buf);
  strcat(input_str->input_parms, "\n");
  
  if (input_str->xcalbox > 0) {

      sprintf(str_buf, "XCALBOX = %d", (int)input_str->xcalbox);
      strcat(input_str->input_parms, str_buf);
      strcat(input_str->input_parms, "\n");

      sprintf(str_buf, "XCALBOXCENTER = %d, %d",
      (int)input_str->xcalboxcenter[0], (int)input_str->xcalboxcenter[1]);
      strcat(input_str->input_parms, str_buf);
      strcat(input_str->input_parms, "\n");

      sprintf(str_buf, "XCALPERVALID = %d", (int)input_str->xcalpervalid);
      strcat(input_str->input_parms, str_buf);
      strcat(input_str->input_parms, "\n");
  }

  return 0;
}




int msl2cal_get_item(char *arg, inputstr *input_str)
{
  char *tmp_str; 
  char *tmp_ptr;
  char keyword [20]; 
  char str_buf [20];
  char parm_str[4096];
  char tmp_file[FILENAME_MAX];
  int  i, iret, ilen1;
  int32_t  ltmp, itmp;
  FILE  *fp;
  
    

  if ((tmp_str = strchr(arg, '=')) == NULL) {
    HY1C_out("Invalid argument %s\n", arg);
    return -1;
  }

  ilen1 = tmp_str-arg;
  strncpy(keyword, arg, ilen1);
  while (isspace(keyword[ilen1-1]))
    ilen1--;
  keyword[ilen1] = '\0';
  strcpy(parm_str, tmp_str+1);

  /* change keyword to lower case */
  tmp_str = keyword;
  while (*tmp_str != '\0') {
    if (isupper(*tmp_str)) *tmp_str = tolower(*tmp_str);
    tmp_str++;
  }

  if (strcmp(keyword, "par") == 0) {
    iret = msl2cal_par_file(parm_str, input_str);
    return iret;

  } else if (strcmp(keyword, "ifile") == 0) {
    parse_file_name(parm_str, tmp_file);
    strcpy((input_str->ifile)[0], tmp_file);

  } else if (strncmp(keyword, "ifile", 5) == 0) {

    for (i=0; i<MAXNFILES; i++) {
      if (i<9)
        sprintf(str_buf, "ifile%1d", i+1);
      else if (i<99)
        sprintf(str_buf, "ifile%2d", i+1);
      else
        sprintf(str_buf, "ifile%3d", i+1);
 
      if (strcmp(keyword, str_buf) == 0) {
        parse_file_name(parm_str, tmp_file);
        strcpy((input_str->ifile)[i], tmp_file);
        break;
      }
    }
    if (i >= MAXNFILES) goto Invalid_return;

  } else if (strcmp(keyword, "ilist") == 0) {

    parse_file_name(parm_str, tmp_file);
    if ((fp = fopen(tmp_file, "r")) == NULL) {
   	HY1C_out("-E- %s line %d: Unable to open input file list %s\n", __FILE__,__LINE__, tmp_file);
	goto Invalid_return;
    }
    tmp_file[0] = '\x0';
    for (i=0; i<MAXNFILES; i++) {
      if (fscanf(fp, "%s\n", tmp_file) != EOF)
      	strcpy((input_str->ifile)[i], tmp_file);
      else
        break;
    }
    fclose(fp);

  } else if (strcmp(keyword, "ofile") == 0) {
    parse_file_name(parm_str, tmp_file);
    strcpy(input_str->ofile, tmp_file);
 
  } else if (strcmp(keyword, "flaguse") == 0) {
    parse_file_name(parm_str, tmp_file);
    strcpy(input_str->flaguse, tmp_file);

  } else if (strcmp(keyword, "spixl") == 0) {
    input_str->spixl = atoi(parm_str);

  } else if (strcmp(keyword, "epixl") == 0) {
    input_str->epixl = atoi(parm_str);

  } else if (strcmp(keyword, "dpixl") == 0) {
    input_str->dpixl = atoi(parm_str);

  } else if (strcmp(keyword, "sline") == 0) {
    input_str->sline = atoi(parm_str);

  } else if (strcmp(keyword, "eline") == 0) {
    input_str->eline = atoi(parm_str);

  } else if (strcmp(keyword, "dline") == 0) {
    input_str->dline = atoi(parm_str);

  } else if (strcmp(keyword, "xcalbox") == 0) {
    input_str->xcalbox = (int32_t)atoi(parm_str);

  }  else if (strcmp(keyword, "xcalboxcenter") == 0) {
     tmp_ptr = parm_str;
     while (tmp_ptr[0] == '(' || tmp_ptr[0] == '[' || tmp_ptr[0] == '"' ||
            tmp_ptr[0] == '\'')
       tmp_ptr++;

     sscanf(tmp_ptr, "%d", &ltmp);
     input_str->xcalboxcenter[0] = ltmp;
  
     itmp = 1;
     while ((tmp_ptr = strchr(tmp_ptr, ',')) != NULL) {
       tmp_ptr++;
       sscanf(tmp_ptr, "%d", &ltmp);
       input_str->xcalboxcenter[itmp] = ltmp;
       itmp++;
       if (itmp > 2) break;
     }

  } else if (strcmp(keyword, "xcalpervalid") == 0) {
    input_str->xcalpervalid = (int32_t)atoi(parm_str);

  } else {
    goto Invalid_return;
  }

  return 0;


Invalid_return:
  HY1C_out("Invalid argument \"%s\"\n", arg);
  return(FATAL_ERROR);
}




int msl2cal_par_file(char *pfile, inputstr *input_str)
{
  FILE *fp;
  char arg[2048];
  int  iret;

  if ((fp = fopen(pfile, "r")) == NULL) {
    HY1C_out("Error on opening the parameter file - %s\n", pfile);
    return -1;
  }

  while ((fgets(arg, 2047, fp)) != NULL) {
    /* skip the comment or blank line */
    if (arg[0] == '#' || arg[0] == ';' || arg[0] == ' ' || arg[0] == '\0' ||
        arg[0] == '\n')   
      continue;

    arg[strlen(arg)-1] = '\0';    /* replace the last char new_line to NULL */
    iret = msl2cal_get_item(arg, input_str);
    if (iret != 0) {
      fclose(fp);
      return -1;
    }
  }

  fclose(fp);
  return 0;
}


